﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using crmbl.Azure.Globals;
using crmbl.Azure.Metadata.Globals;

namespace crmbl.Azure.Configuration.Processor
{
    public class EventLogProcessor : IDisposable
    {
        private const String WINDOWSEVENT_TABLENAME = "WADWindowsEventLogsTable";

        String _storageAccountName;
        String _storageAccountKey;
        Guid _storageAccountId;

        TableServiceContext _tableContext;

        ApplicationHelper _app;

        #region Constructors

        public EventLogProcessor(Guid storageAccountId, String storageAccountName, String StorageAccountPrimaryKey, String targetDataSourceConnectionString)
        {
            _storageAccountName = storageAccountName;
            _storageAccountKey = StorageAccountPrimaryKey;

            _storageAccountId = storageAccountId;

            // Constuct a new application helper
            _app = new ApplicationHelper(targetDataSourceConnectionString);

            // Initiate a new Table Context
            _tableContext = AzureTableHelper.GetTableContext(_storageAccountName, _storageAccountKey);
        }
        #endregion

        #region Public Methods

        public void Process()
        {
            // Connect to configuration database, get the latest id
            GenericTableEntity lastUpdatedConfig = _app.GetTableObjectMetadata(_storageAccountId, WINDOWSEVENT_TABLENAME);

            long maxPartitionKey = long.Parse(lastUpdatedConfig.PartitionKey);
            String maxRowKey = lastUpdatedConfig.RowKey;

            foreach (WindowsEventLogEntity winEventLog in GetWindowsEventLogsToProcess(lastUpdatedConfig.PartitionKey, lastUpdatedConfig.RowKey))
            {
                try
                {
                    // Write the Windows Event
                    _app.WriteEventLogEntry(winEventLog);

                    // Update if newer
                    long n = long.Parse(winEventLog.PartitionKey);
                    if (n >= maxPartitionKey)
                    {
                        maxPartitionKey = n;
                        maxRowKey = winEventLog.RowKey;
                    }
                }
                catch (Exception ex)
                {
                    //TODO: Log an error
                    Console.WriteLine(ex.ToString());
                }
            }

            // Update the TableDownload
            _app.UpdateTableObjectUpdate(_storageAccountId, WINDOWSEVENT_TABLENAME, "0" + maxPartitionKey.ToString(), maxRowKey);
        }

        #endregion

        #region Private Methods

        private List<WindowsEventLogEntity> GetWindowsEventLogsToProcess(String startingParitionKey, String startingRowKey, int top = 0)
        {
            IQueryable<WindowsEventLogEntity> eventLogsTable = _tableContext.CreateQuery<WindowsEventLogEntity>(WINDOWSEVENT_TABLENAME);

            var newCounters = (from r in eventLogsTable
                               where r.PartitionKey.CompareTo(startingParitionKey) >= 0
                               select r);

            if (top > 0)
            {
                return newCounters.Take(top).ToList();
            }

            List<WindowsEventLogEntity> l = newCounters.ToList();

            if (newCounters.ToList().Count > 0)
            {
                var containsLastRow = from i in newCounters
                                      where i.RowKey == startingRowKey
                                            & i.PartitionKey == startingParitionKey
                                      select i;

                // Contains the last processed row?
                if (containsLastRow.ToList().Count == 0)
                {
                    // does not contain the last row
                    return newCounters.ToList();
                }
            }

            return new List<WindowsEventLogEntity>();
        }

        #endregion

        #region Deconstuctors

        void IDisposable.Dispose()
        {
            try
            {
                _app.Dispose();
            }
            catch (Exception) { } //ignore exceptions

        }

        #endregion
    }
}
